home *** CD-ROM | disk | FTP | other *** search
/ Packard Bell - Internet on a CD / internet on a cd.cdr / Internet / sites / Clementine_NASA / clemdsrc.hqx / WriteGIF.c < prev   
Encoding:
C/C++ Source or Header  |  1994-08-21  |  29.6 KB  |  966 lines

  1. /*  
  2. **************************************************************************
  3. *
  4. *        -----------------    
  5. *        |   WriteGIF    |
  6. *        -----------------        
  7. *    
  8. *_TITLE WriteGIF writes a CompuServe GIF image when passed image data and size.
  9. *
  10. *_DESC  WriteGIF writes a CompuServe GIF image when a GIF file pointer, 
  11. *         an image buffer containing raw image data, number of lines,
  12. *         and sample per line is passed to the function writegif.
  13. *         The image buffer is assumed to contain a 256 gray scaled
  14. *         image with one byte of data representing one sample.
  15. *
  16. *         The GIF file written uses 87A GIF specs set up by
  17. *         CompuServe.  Under those specs its writes a GIF header,
  18. *         a logical screen descriptor, a global color table, an
  19. *         image descriptor, and the compressed image data.  It
  20. *         is highly recommended that anyone attempting to decipher
  21. *         this code should read the CompuServe specs on GIF files
  22. *         since many of the terms and names are taken from those
  23. *         specs (a familiarity with LZW compression might also be
  24. *         useful).
  25. *
  26. *         "The Graphics Interchange Format(c) is the Copyright property
  27. *         of CompuServe Incorporated.  GIF(sm) is a Service Mark
  28. *         property of CompuServe Incorporated."
  29. *    
  30. *_HIST  MAY 31 1994  David Larsen, USGS, Flagstaff Original Version
  31. *
  32. ***************************************************************************
  33. */
  34.  
  35. #include <stdio.h>
  36.  
  37. /*
  38. ******************************************************************************
  39. **
  40. **    Defined Macros
  41. **
  42. ******************************************************************************
  43. */
  44.  
  45.  
  46. /*misc macros*/
  47. #define LO_BYTE_16BIT                  (GIFdata & 255)
  48. #define HI_BYTE_16BIT                  ((GIFdata & 65280)/256)
  49. #define HEADER                    "GIF87a"
  50.  
  51. /*Error Codes*/
  52. #define ERROR                    -1    
  53. #define NO_ERROR                 0    
  54.  
  55. /*GIF image macros*/
  56. #define GIF_TRAILER                59    
  57. #define LOGICAL_SCREEN_PACKED_BIT_FIELDS    247    
  58. #define BACKGROUND_COLOR_INDEX            0
  59. #define PIXEL_ASPECT_RATIO            0    
  60. #define IMAGE_SEPARATOR                    44    
  61. #define IMAGE_LEFT_POSITION            0
  62. #define IMAGE_TOP_POSITION            0
  63. #define IMAGE_DESCRIPTOR_PACKED_BIT_FIELDS    0
  64. #define IMAGE_BUFFER_SIZE            150000
  65. #define BLOCK_TERMINATOR            0
  66. #define TABLE_SIZE                    27701 /*4099 25013 30011 40007 50021 */    
  67. #define FIRST_NEW_OUTPUT_CODE                258    
  68. #define BUFFER_SIZE                251
  69. #define MIN_CODE_SIZE                8
  70. #define START_CODE_BIT_SIZE            9
  71. #define CLEAR_CODE                    256    
  72. #define MAX_STRING_CODE                4096
  73. #define OVERFLOW                4096
  74. #define LZW_TERMINATOR_CODE            257
  75.  
  76. /*set up macros for a BOOLEAN type*/
  77. #define BOOLEAN                    char
  78. #define TRUE                    1
  79. #define FALSE                    0
  80.  
  81. /* Macro functions used in debugging */
  82. #define xx                     printf("xx\n")
  83. #define yy                     printf("yy\n")
  84. #define zz                     printf("zz\n")
  85.  
  86. void errmsg();
  87. extern long int resnumq;
  88.  
  89. /*
  90. ******************************************************************************
  91. **
  92. **    Type Definitions
  93. **
  94. ******************************************************************************
  95. */
  96.  
  97. /*a type definition for a string table entry in the 
  98.   string table array (which is called HashTable in 
  99.   this program)*/
  100. struct StrTabNode{    long         StartString; /*pointer to the string 
  101.                                in table*/
  102.             int        StringSize;  /*size of the string in 
  103.                                table*/
  104.             int        StringCode;  /*the code given to the 
  105.                                string in table*/
  106.          };
  107. typedef struct StrTabNode StringTabNode; /*gives an easy name to 
  108.                        struct StrTabNode*/
  109. /*
  110. ******************************************************************************
  111. **
  112. **    Global Variables
  113. **
  114. ******************************************************************************
  115. */
  116. Handle         HashTable;     
  117. Handle         ImageBuffer;     
  118. int         I;
  119.  
  120. /*
  121. **************************************************************************
  122. **
  123. **    Prototypes
  124. **
  125. **************************************************************************
  126. */    
  127.  
  128.  /*Function that makes the GIF file. 
  129.    It returns an error code*/
  130. int         writegif(FILE *, long, long, Handle);
  131.  
  132.  /*Function that writes a header "GIF87A" to GIF file. 
  133.    It returns an error code*/
  134. int         WriteHeader(FILE *);
  135.  
  136.  /*Function that writes the Logical Screen Descriptor to GIF file. 
  137.    It returns an error code*/
  138. int         WriteLogicalScreenDescriptor(FILE *, long, long);
  139.  
  140.  /*Function that writes the Global Color Table to GIF file. 
  141.    It returns an error code*/
  142. int         WriteGlobalColorTable(FILE *);
  143.  
  144.  /*Function that writes the image data to GIF file. 
  145.    It returns an error code*/
  146. int         WriteImage( FILE *, long , long );
  147.  
  148.  /*Function that writes the Image Descriptor to GIF file. 
  149.    It returns an error code*/
  150. int         WriteImageDescriptor(FILE *, long, long);
  151.  
  152.  /*Function that compresses the image and writes it to GIF file. 
  153.    It returns an error code*/
  154. int        WriteImageDataBlock(FILE *,long, long);
  155.  
  156.  /*Function that compares two LZW strings.  It returns TRUE if they are
  157.    the same and FALSE if they are not*/
  158. BOOLEAN     CompareString(unsigned char *, long , int, long , int );
  159.  
  160.  
  161.  /*procedure that puts a string and its string code into the hash
  162.    table*/
  163. void         PutInTable(unsigned char *, long, int, int, StringTabNode *);
  164.  
  165.  /*procedure that initializes the hash table to nothing*/
  166. void         InitTable(StringTabNode *);
  167.  
  168.  /*function that puts bytes into the GIF buffer.  If it fills up it
  169.    writes the buffer to the GIF file. It returns an error code*/
  170. int         PutInGIFBuffer(FILE *,  unsigned char *, unsigned char, int *);
  171.  
  172.  /*function that finds a string in the hash table.  It returns its
  173.    string code if it is in the table and NULL if not*/
  174. int         FindInTable(unsigned char *, long, int, StringTabNode *);
  175.  
  176.  /*function that packs string codes and puts them into the GIF buffer.
  177.    It returns an error code*/
  178. int         WriteToGIF(FILE *, unsigned char *,unsigned int,unsigned char *,unsigned int *,int,int *);
  179.  
  180.  /*function that writes 8 bit sized data to the open GIF file
  181.    It returns an error code*/
  182. int         WriteGIFdata8(FILE *, unsigned char);
  183.  
  184.  /*function that writes 16 bit sized data to the open GIF file as lo
  185.    byte and hi byte It returns an error code*/
  186. int         WriteGIFdata16(FILE *, unsigned int);
  187.  
  188.  
  189.  
  190.  
  191. /*
  192. *************************************************************************
  193. **
  194. **    This function calls all other functions in this file to
  195. **    create the GIF file.  This function outputs error messages if
  196. **    a problem occures during the creation of the GIF.  It returns
  197. **    ERROR if there was a problem and NO_ERROR if the GIF was created
  198. **    ok.
  199. **
  200. *************************************************************************
  201. */
  202. int writegif(    FILE *        GIFfile,    /*pointer to GIF file*/
  203.              long        Lines,      /*number of lines in image*/
  204.         long        Samples,    /*number of samples per line*/
  205.         Handle        ImageB
  206.         
  207.          )
  208. {
  209.  
  210.    I=0;
  211. /*   printf("Writing GIF file.\n");  */
  212.  
  213.    HashTable     = NewHandle(sizeof(StringTabNode[TABLE_SIZE+OVERFLOW]));
  214.                                   /*The String Table*/
  215.    ImageBuffer     = ImageB;
  216.       /*Write the Header block. Print an error message and return the appropriate 
  217.      error code if there was an error*/   
  218.    if(WriteHeader(GIFfile)){
  219.       errmsg("**>ERROR writing the GIF file.\n",&resnumq);
  220.       return ERROR;
  221.    } /*end if*/
  222.  
  223.    /*Write the Logical Screen Descriptor block Print an error message and 
  224.      return the appropriate error code if there was an error*/   
  225.    if(WriteLogicalScreenDescriptor(GIFfile, Lines, Samples)){
  226.       errmsg("**>ERROR writing the GIF file.\n",&resnumq);
  227.       return ERROR;
  228.    } /*end if*/
  229.  
  230.    /*Write the Global Color Table block.  Print an error meaasage and 
  231.      return the appropriate error code if there was an error*/   
  232.    if(WriteGlobalColorTable(GIFfile)){
  233.       errmsg("**>ERROR writing the GIF file.\n",&resnumq);
  234.       return ERROR;
  235.    } /*end if*/
  236.  
  237.    /*Write the Image Descriptor block, compress the image,  and write the 
  238.      compressed image data.  Print an error message and return the appropriate
  239.      error code if there was an error*/   
  240.    if(WriteImage( GIFfile, Lines, Samples)){
  241.       errmsg("**>ERROR writing the GIF file.\n",&resnumq);
  242.       return ERROR;
  243.    } /*end if*/
  244.  
  245.    /*Write the Trailer to indicate the end of the image.  Print an error
  246.      message return the appropriate error code if there was an error*/   
  247.    if(WriteGIFdata8(GIFfile, GIF_TRAILER)) {
  248.       errmsg("**>ERROR writing the GIF file.\n",&resnumq);
  249.       return ERROR;
  250.    } /*end if*/
  251.  
  252.  
  253.    /*if no errors occured during GIF creation then print a message and return 
  254.      the appropriate error code */
  255. /*   printf("GIF file was successfully written.\n");  */
  256.    return NO_ERROR; 
  257. }
  258.  
  259.  
  260.  
  261.  
  262. /*
  263. **************************************************************************
  264. **
  265. **     This function writes the header portion of the GIF file.  If an
  266. **    error occured it returns ERROR otherwise NO_ERROR.
  267. **
  268. **************************************************************************
  269. */
  270. int WriteHeader(FILE * GIFfile  /*pointer to the GIF file*/)
  271. {
  272.    char HeaderString[7] = HEADER;
  273.    int i;
  274.  
  275.    /*write header data.
  276.  
  277.      NOTE: the sizeof operator only indicates 6 characters of the string to 
  278.            write because it leaves off the string terminator
  279.    */
  280.    /*Write the Trailer to indicate the end of the image.  Print an error
  281.      message return the appropriate error code if there was an error*/   
  282.    for(i = 0; i < 6; i++)
  283.       if(WriteGIFdata8(GIFfile, HeaderString[i])) 
  284.          return ERROR;
  285.      
  286.    return NO_ERROR;
  287.  
  288. }
  289.  
  290.  
  291.  
  292. /*
  293. **************************************************************************
  294. **
  295. **     This function writes the logical screen descriptor portion of the 
  296. **    GIF file.  If an error occured it returns ERROR otherwise NO_ERROR.
  297. **
  298. **************************************************************************
  299. */
  300. int WriteLogicalScreenDescriptor(    FILE * GIFfile, /*pointer to GIF file*/
  301.                      long     Lines,  /*number of lines 
  302.                               in image*/
  303.                      long     Samples /*number of samples
  304.                               per line*/
  305.                 )
  306. {
  307.    /*write the width of the display device in pixels and return the
  308.      appropriate error code if there is an error*/
  309.    if(WriteGIFdata16(GIFfile, Samples))
  310.       return ERROR;
  311.  
  312.    /*write the height of the display device in pixels and return the 
  313.      appropriate error code if there is an error*/
  314.    if(WriteGIFdata16(GIFfile, Lines))
  315.       return ERROR;
  316.  
  317.  
  318.    /*write the packed bit fields for: 
  319.  
  320.      Global Color Table Flag     (bit  7  ),  
  321.      Color Resolution        (bits 6-4),  
  322.      Sort Flag             (bit  3  ), and 
  323.      Size of Global Color Table (bits 2-0).  
  324.  
  325.      Return the appropriate error code if there is an error
  326.    */
  327.    if(WriteGIFdata8(GIFfile, LOGICAL_SCREEN_PACKED_BIT_FIELDS))
  328.       return ERROR;
  329.  
  330.    /*write the background color index and return the 
  331.      appropriate error code if there is an error*/
  332.    if(WriteGIFdata8(GIFfile, BACKGROUND_COLOR_INDEX))
  333.       return ERROR;
  334.  
  335.    /*write the pixel aspect ratio and return the 
  336.      appropriate error code if there is an error*/
  337.    if(WriteGIFdata8(GIFfile, PIXEL_ASPECT_RATIO))
  338.       return ERROR;
  339.  
  340.    /*return the error code for no error if everything ran ok*/
  341.    return NO_ERROR;
  342. }
  343.  
  344.  
  345.  
  346. /*
  347. **************************************************************************
  348. **
  349. **     This function writes the global color table portion of the 
  350. **    GIF file.  If an error occured it returns ERROR otherwise NO_ERROR.
  351. **
  352. **************************************************************************
  353. */
  354. int WriteGlobalColorTable(FILE * GIFfile /*pointer to GIF file*/)
  355. {
  356.    int i;
  357.  
  358.    /*write the color table
  359.  
  360.      NOTE: since this is a 256 grey scaled image the red, green, and blue
  361.            colors will all have the same intensity for each table entry.
  362.            This type of grey scale is put the table from intesities 0 to 255.
  363.    */ 
  364.    for(i = 0; i <= 255; i++) { 
  365.       if(WriteGIFdata8(GIFfile, i))
  366.          return ERROR;
  367.       if(WriteGIFdata8(GIFfile, i))
  368.          return ERROR; 
  369.       if(WriteGIFdata8(GIFfile, i))
  370.          return ERROR;
  371.    } /*end for*/     
  372.    /*return the error code for no error if everything ran ok*/
  373.    return NO_ERROR;
  374. }
  375.  
  376.  
  377.  
  378. /*
  379. **************************************************************************
  380. ** 
  381. **     This function writes the image data portion of the 
  382. **    GIF file.  If an error occured it returns ERROR otherwise NO_ERROR.
  383. **    It does this by calling the functions in this file that writes
  384. **    that data.
  385. **
  386. **************************************************************************
  387. */
  388. int WriteImage(        FILE * GIFfile,    /*pointer to GIF file*/
  389.         long Lines,    /*number of lines in image*/ 
  390.         long Samples     /*number of samples per line*/    
  391.           )
  392. {
  393.  
  394.    /*Write the Image Descriptor block and return the appropriate error code 
  395.      if there was an error*/   
  396.    if(WriteImageDescriptor(GIFfile, Lines, Samples))
  397.       return ERROR;
  398.  
  399.    /*Write the Image Data block and return the appropriate error code 
  400.      if there was an error*/   
  401.    if(WriteImageDataBlock(GIFfile, Lines, Samples))
  402.       return ERROR;
  403.  
  404.    /*return the error code for no error if everything ran ok*/
  405.    return NO_ERROR;
  406. }
  407.  
  408.  
  409.  
  410.  
  411. /*
  412. ***************************************************************************
  413. **
  414. **     This function writes the image descriptor portion of the 
  415. **    GIF image.  If an error occured it returns ERROR otherwise NO_ERROR.
  416. **
  417. ***************************************************************************
  418. */
  419. int WriteImageDescriptor(    FILE *         GIFfile, /*pointer to GIF file*/
  420.                 long        Lines,   /*number of lines
  421.                                in image*/
  422.                 long        Samples  /*number of samples 
  423.                                per line*/
  424.             )
  425. {
  426.    /*write the image separator and return the 
  427.      appropriate error code if there is an error*/
  428.    if(WriteGIFdata8(GIFfile, IMAGE_SEPARATOR))
  429.       return ERROR;
  430.  
  431.    /*write the image left position and return the 
  432.      appropriate error code if there is an error*/
  433.    if(WriteGIFdata16(GIFfile, IMAGE_LEFT_POSITION))
  434.       return ERROR;
  435.  
  436.    /*write the image top position and return the 
  437.      appropriate error code if there is an error*/
  438.    if(WriteGIFdata16(GIFfile, IMAGE_TOP_POSITION))
  439.       return ERROR;
  440.  
  441.    /*write the image width and return the 
  442.      appropriate error code if there is an error*/
  443.    if(WriteGIFdata16(GIFfile, Samples))
  444.       return ERROR;
  445.  
  446.    /*write the image height and return the 
  447.      appropriate error code if there is an error*/
  448.    if(WriteGIFdata16(GIFfile, Lines))
  449.       return ERROR;
  450.  
  451.    /*write the packed bit fields for: 
  452.  
  453.      Local Color Table Flag     (bit  7  ),  
  454.      Interlaced    Flag        (bit  6  ),
  455.      Sort Flag             (bit  5  ), 
  456.      Reserved             (bits 4-3), and
  457.      Size of Local Color Table  (bits 2-0).  
  458.  
  459.      Return the appropriate error code if there is an error
  460.    */
  461.    if(WriteGIFdata8(GIFfile, IMAGE_DESCRIPTOR_PACKED_BIT_FIELDS))
  462.       return ERROR;
  463.  
  464.    /*return the error code for no error if everything ran ok*/
  465.    return NO_ERROR;
  466. }
  467.  
  468.  
  469.  
  470. /*
  471. **************************************************************************
  472. **
  473. **     This function writes the image data block portion of the 
  474. **    GIF image.  If an error occured it returns ERROR otherwise NO_ERROR.
  475. **    This function does the LZW compression of the image data and
  476. **    then writes it to the GIF file.  It should be noted that a simple 
  477. **    hashing function is used to index into the LZW string table in 
  478. **      order to speed the compression process.  It uses linear probing
  479. **    to find an item if a collision occures.  
  480. **
  481. **    NOTE: This file uses CompuServe terminology and standard LZW
  482. **          terminology when ever possible.  The term string is used
  483. **          here because of this.  It should be noted that this is
  484. **          NOT an ascii string but rather raw data from the ImageBuffer.
  485. **          In order to fully understand how this code works it is recommended
  486. **          that one reads the CompuServe GIF specs before deciphering this 
  487. **          code.
  488. **
  489. **************************************************************************
  490. */
  491. int WriteImageDataBlock(    FILE *         GIFfile,/*pointer to GIF file*/
  492.                 long        Lines,  /*number of lines*/
  493.                     long        Samples /*number of samples 
  494.                                per line*/
  495.             
  496.                        )
  497. {
  498.    long            StartString     = 0;            /*a pointer to iterate
  499.                              thru the raw data*/
  500.    int             StringSize     = 1;            /*used to index off Start
  501.                              String*/
  502.    int             StringCode     = FIRST_NEW_OUTPUT_CODE; 
  503.                                /*codes to put in string
  504.                                  table*/
  505.    int             ByteCount    = 0;           /*holds the current 
  506.                              location in the 
  507.                              GIFBuffer*/
  508.    unsigned int     LastPos        = 0;            /*holds the location 
  509.                              of the bit where to 
  510.                              write the next byte 
  511.                                         in GIFBuffer*/
  512.    unsigned char     LeftOver        = 0;           /*holds the left over 
  513.                              data that needs to be 
  514.                              put in GIFBuffer*/
  515.    int             CodeBitSize     = START_CODE_BIT_SIZE;
  516.                                /*Holds the current bit 
  517.                              size of the StringCode
  518.                              (for GIFs this is 
  519.                              variable length)*/
  520.    int             CurrentCode;                /*Holds the currents 
  521.                              string code pulled out
  522.                              of the HashTable*/
  523.    int             PreviousCode;                /*Holds the previous 
  524.                              string code pulled 
  525.                              out of the HashTable*/
  526.    int             i;                    /*an iterater to go thru
  527.                              loops*/
  528.    long            ImageIndex    = 0;
  529.    unsigned char *    tempptr;
  530.    unsigned char     GIFBuffer[BUFFER_SIZE];        /*a buffer to hold GIF 
  531.                                     image data before 
  532.                              writing it*/
  533.    
  534.    
  535.    MoveHHi(ImageBuffer);
  536.    MoveHHi(HashTable);
  537.    
  538.  
  539.    /*write the minimum code size and return the 
  540.      appropriate error code if there is an error*/
  541.    if(WriteGIFdata8(GIFfile, MIN_CODE_SIZE))
  542.         return ERROR;
  543.  
  544.    /*write the clear code to GIF file and return the 
  545.      appropriate error code if there is an error*/
  546.    if(WriteToGIF(GIFfile, GIFBuffer, CLEAR_CODE, &LeftOver, &LastPos,
  547.           CodeBitSize, &ByteCount))
  548.       return ERROR;
  549.  
  550.    /*initialize the HashTable*/
  551.    HLock(HashTable);
  552.    InitTable((StringTabNode *)*HashTable);
  553.    HUnlock(HashTable);
  554.  
  555. /*This is the main loop that goes thru the raw data in the ImageBuffer
  556.   and compresses it*/
  557.  
  558.    /*loop from the begining address of ImageBuffer to the ending address*/
  559.    while(ImageIndex <= Lines*Samples){
  560.       /*Pull the current code out of the Hash Table according to the
  561.         current string*/
  562.       HLock(HashTable);
  563.       HLock(ImageBuffer);
  564.       CurrentCode = FindInTable((unsigned char *)*ImageBuffer, StartString, StringSize, (StringTabNode *)*HashTable);
  565.       HUnlock(HashTable);
  566.       HUnlock(ImageBuffer);
  567.       /*checks to see if the current code was in the hash table*/
  568.       if(CurrentCode == -1){
  569.  
  570.      /*write the PreviousCode to GIF file and return the appropriate
  571.        error code if there was an error*/
  572.          if(WriteToGIF(GIFfile, GIFBuffer, (unsigned int)PreviousCode, &LeftOver, &LastPos,
  573.             CodeBitSize, &ByteCount))
  574.          return ERROR;
  575.      
  576.          /*increase the bit size for the string code if it outgrows the
  577.        old size*/
  578.      if(StringCode >= (1 << CodeBitSize))
  579.         CodeBitSize++;
  580.  
  581.      /*put the newest string in the table and its string code*/
  582.      HLock(HashTable);
  583.      HLock(ImageBuffer);
  584.      PutInTable((unsigned char *)*ImageBuffer, StartString, StringSize, StringCode, (StringTabNode *)*HashTable);
  585.      HUnlock(HashTable);
  586.      HUnlock(ImageBuffer);
  587.  
  588.      /*update string code and look at a new string*/
  589.          StringCode++;
  590.      StartString += StringSize - 1;
  591.      ImageIndex--;
  592.      StringSize = 0;
  593.        } /*end if*/
  594.  
  595.        /*remember CurrentCode for next time thru loop*/
  596.        PreviousCode = CurrentCode;
  597.  
  598.        /*increase string size for next time thru loop*/
  599.        StringSize++;
  600.        ImageIndex++;
  601.  
  602.        /*this checks to see if the StringCode larger than its max size.
  603.          If so it writes the clear code to the GIF and resets everything*/     
  604.        if(StringCode > MAX_STRING_CODE){
  605.  
  606.           /*write the clear code to GIF file and return the 
  607.             appropriate error code if there is an error*/
  608.           if(WriteToGIF(GIFfile, GIFBuffer, CLEAR_CODE, &LeftOver, 
  609.                          &LastPos, CodeBitSize - 1, &ByteCount))
  610.              return ERROR;
  611. /*xx;*/
  612.           /*reset everything to initial values*/
  613.         StringSize     = 1;
  614.           StringCode     = FIRST_NEW_OUTPUT_CODE;
  615.          CodeBitSize   = START_CODE_BIT_SIZE;
  616.  
  617.          HLock(HashTable);
  618.       InitTable((StringTabNode *)*HashTable);
  619.       HUnlock(HashTable);
  620.  
  621.        } /*end if*/
  622.      } /*end while*/
  623.  
  624.    /*write the last string code found to GIF file and return the 
  625.      appropriate error code if there is an error*/
  626.    if(WriteToGIF(GIFfile, GIFBuffer, (unsigned int)CurrentCode, &LeftOver, &LastPos,
  627.          CodeBitSize, &ByteCount))
  628.       return ERROR;
  629.  
  630.    /*write the code to terminate image data to GIF file and return the 
  631.      appropriate error code if there is an error*/
  632.    if(WriteToGIF(GIFfile, GIFBuffer, LZW_TERMINATOR_CODE, &LeftOver, &LastPos, 
  633.          CodeBitSize, &ByteCount))
  634.       return ERROR;
  635.  
  636.    /*place the left over bits from compression in the GIF buffer*/
  637.    PutInGIFBuffer(GIFfile, GIFBuffer, LeftOver, &ByteCount);
  638.  
  639.    /*write the GIF buffer to GIF file if needed and return the
  640.      appropriate error code if there was an error*/
  641.    if(ByteCount) {
  642.       if(WriteGIFdata8(GIFfile, ByteCount))
  643.      return ERROR;
  644.       for(i = 0; i < ByteCount; i++)
  645.          if(WriteGIFdata8(GIFfile, GIFBuffer[i]))
  646.         return ERROR;
  647.    } /*end if*/
  648.  
  649.    /*write the BLOCK_TERMINATOR and return the
  650.      appropriate error code if there is an error*/
  651.    if(WriteGIFdata8(GIFfile, BLOCK_TERMINATOR))
  652.       return ERROR;
  653.  
  654.    DisposeHandle(ImageBuffer);
  655.    DisposeHandle(HashTable);
  656.  
  657.    /*normal exit*/
  658.    return NO_ERROR;   
  659. }
  660.  
  661.  
  662.    
  663.  
  664.  
  665.      
  666. /*
  667. **************************************************************************
  668. **
  669. **    This is used to compare LZW strings(see WriteImageDataBlock). Instead 
  670. **    of a regular C string terminator it uses size to indicate how long
  671. **    the strings is (similar to a pascal string) because a NULL is
  672. **    considered valid raw data.  This is used to determine if two
  673. **    strings or string segments are the same.  If they are then 
  674. **    it returns TRUE, otherwise it returns FALSE.  The second 
  675. **    string may contain a NULL pointer; if it does a FALSE is returned 
  676. **    regardless.
  677. **
  678. **************************************************************************
  679. */
  680. BOOLEAN CompareString(  unsigned char *        ImageBuffer,
  681.             long             String1,/*first string*/
  682.             int             Size1,  /*size of first string*/
  683.             long             String2,/*second string*/
  684.             int             Size2   /*size of second 
  685.                               string*/
  686.              )
  687. {
  688.    int i;
  689.  
  690.    /*see if string sizes are differnt or a NULL is found. If so FALSE 
  691.      is returned*/
  692.    if((Size1 != Size2) || (Size2 == 0))
  693.       return FALSE;
  694.       
  695.    /*compare the strings*/ 
  696.    for(i = 0; i < Size1; i++)
  697.       if(ImageBuffer[String1 + i] != ImageBuffer[String2 + i])
  698.      return FALSE;
  699.  
  700.    /*return here if strings are the same*/
  701.    return TRUE;
  702. }
  703.  
  704.  
  705.  
  706.  
  707. /*
  708. **************************************************************************
  709. **
  710. **    This puts a LZW string into the string table using a hashing
  711. **    function.
  712. **
  713. **************************************************************************
  714. */
  715. void PutInTable(    unsigned char *        ImageBuffer,
  716.             long             StringToPut,/*the string*/
  717.             int             StringSize, /*size of string*/
  718.             int             StringCode, /*code to represent
  719.                                   string in GIF*/
  720.             StringTabNode *        HashTable   /*the hash table*/
  721.            )
  722. {
  723.    /*derive a location in the HashTable*/
  724.    long Location = (((long)ImageBuffer[StringToPut] * (long)ImageBuffer[StringToPut + 1]) * (long)StringSize * 101) % TABLE_SIZE;
  725.  
  726.    /*see if a collision occured and find next blank spot*/
  727.    while(HashTable[Location].StringSize != 0) {
  728. /*printf("%d ",I++);*/
  729.       Location ++;
  730. }
  731.    /*place string and its string code in HashTable*/ 
  732.    HashTable[Location].StartString = StringToPut;
  733.    HashTable[Location].StringSize = StringSize;
  734.    HashTable[Location].StringCode  = StringCode;
  735.    
  736.    return;
  737. }
  738.  
  739.  
  740.  
  741.  
  742. /*
  743. **************************************************************************
  744. **
  745. **    This initializes the string table to contain nothing.
  746. **
  747. **************************************************************************
  748. */
  749. void InitTable(StringTabNode * HashTable /*the hash table*/)
  750. {
  751.     int i;
  752.  
  753.    /*initialize the HashTable to zero length strings*/
  754.    for(i = 0; i < TABLE_SIZE + OVERFLOW; i++)
  755.       HashTable[i].StringSize = 0;
  756.     
  757.    return;
  758. }
  759.  
  760.  
  761.  
  762. /*
  763. **************************************************************************
  764. **
  765. **    This puts GIF variable length codes into a buffer.   If the
  766. **    buffer gets full it writes it to the GIF file and clears the
  767. **    buffer.
  768. **
  769. **************************************************************************
  770. */
  771. int PutInGIFBuffer(    FILE *         GIFfile,   /*pointer to GIF file*/
  772.             unsigned char * GIFBuffer, /*pointer to GIF buffer*/
  773.                unsigned char     ByteToPut, /*the byte to put in buffer*/
  774.             int *         ByteCount  /*index into the buffer*/
  775.           )
  776. {
  777.    int i;
  778.  
  779.    /*put data into the GIF buffer*/
  780.    GIFBuffer[(* ByteCount)++] = ByteToPut;
  781.  
  782.    /*see if the buffer is full.  if so write it to GIF file*/
  783.    if((* ByteCount) > BUFFER_SIZE - 1) {
  784.      
  785.       /*put buffer size at the top of image data sub-block*/
  786.       if(WriteGIFdata8(GIFfile, BUFFER_SIZE))
  787.      return ERROR;
  788.  
  789.       /*write data to GIF file*/
  790.       for(i = 0; i < BUFFER_SIZE; i++)
  791.          if(WriteGIFdata8(GIFfile, GIFBuffer[i]))
  792.         return ERROR;
  793.  
  794.       /*reset the byte count*/
  795.       (* ByteCount) = 0;
  796.    } /*end if*/
  797.    return NO_ERROR;
  798. }
  799.  
  800.  
  801.  
  802.  
  803. /*
  804. **************************************************************************
  805. **
  806. **    This finds a string in the string table using a hashing function
  807. **    and returns its variable length code as its value. If nothing is
  808. **    found then NULL is returned
  809. **
  810. **    NOTE: the variable length code is returned as an int. The unused
  811. **          bits are set to 0.
  812. **
  813. **************************************************************************
  814. */
  815. int FindInTable(    unsigned char *        ImageBuffer,
  816.             long             StringToFind, /*the string*/
  817.             int             StringSize,   /*size of string*/
  818.             StringTabNode *         HashTable     /*the table to 
  819.                                     look in*/
  820.            )    
  821. {
  822.    int i;
  823.    long Location;
  824.  
  825.  
  826.    /*if string size is one its location is the value of the single string byte*/
  827.    if(StringSize == 1) 
  828.       return (int)ImageBuffer[StringToFind];
  829.  
  830.    /*find string in HashTable*/   
  831.  
  832.    for(Location = (((long)ImageBuffer[StringToFind] * (long)ImageBuffer[StringToFind+1]) * (long)StringSize * 101) % TABLE_SIZE;
  833.        Location < TABLE_SIZE + OVERFLOW;
  834.        Location++)
  835.  
  836.       /*if a StringSize 0 is found then it is not in the table*/
  837.       if(HashTable[Location].StringSize == 0)  
  838.          return (-1);
  839.       
  840.  
  841.           /*if the string is found return its StringCode*/
  842.       else if(CompareString(ImageBuffer, StringToFind, StringSize,
  843.                HashTable[Location].StartString,
  844.                HashTable[Location].StringSize)) 
  845.                   return HashTable[Location].StringCode;
  846.  
  847.    /*went thru the entire string table and nothing was found*/
  848.    return (-1);
  849. }
  850.  
  851.  
  852.  
  853.  
  854. /*
  855. **************************************************************************
  856. **
  857. **    This determines the size of the variable length code and packs
  858. **    it into bytes.  It takes those bytes and puts them in the GIF
  859. **    buffer.  If the last part of the varible length code is
  860. **    not long enough to pack into a byte it is put into a left over
  861. **    variable to be packed into a byte next time through.
  862. **
  863. **************************************************************************
  864. */
  865. int WriteToGIF(        FILE *         GIFfile,     /*pointer to GIF file*/
  866.             unsigned char *    GIFBuffer,   /*pointer to GIF buffer*/
  867.             unsigned int     NewData,     /*data to write to GIF*/
  868.                  unsigned char * LeftOver,    /*left over bits to be 
  869.                                packed next time around*/
  870.             unsigned int *     LastPos,     /*the bit position of the 
  871.                                last bit used*/
  872.             int         CodeBitSize, /*that size of the data to
  873.                                be written*/
  874.             int *         ByteCount    /*index into the GIF 
  875.                                buffer*/
  876.  
  877.           )
  878. {
  879.    /*pack LeftOver with the NewData*/
  880.    unsigned long CodeToWrite = (unsigned long)(((unsigned long)NewData *(1 << (unsigned long)(*LastPos)))|(unsigned long)(*LeftOver));
  881.    int i;
  882.    int TotalBits;
  883.  
  884.    /*write the first byte of the packed string tokens for this round and 
  885.      return the appropriate error code if there is an error*/
  886.    if(PutInGIFBuffer(GIFfile, GIFBuffer, (unsigned char)(CodeToWrite & 255), ByteCount))
  887.       return ERROR;
  888.  
  889.    /*see if only one byte had to be written to GIFBuffer*/
  890.    if ((* LastPos) + CodeBitSize < 16) 
  891.       /*set up LeftOver for next time thru*/
  892.       (* LeftOver) = CodeToWrite >> 8;
  893.    else {
  894.  
  895.       /*write the second byte of the packed string tokens for this round and  
  896.         return the appropriate error code if there is an error*/
  897.       if(PutInGIFBuffer(GIFfile, GIFBuffer, (unsigned char)((CodeToWrite & 65280)/256), 
  898.             ByteCount) )
  899.          return ERROR;
  900.  
  901.       /*set up LeftOver for next time thru*/
  902.       (* LeftOver) = (CodeToWrite >> 16);
  903.    } /*end if*/
  904.  
  905.    /*set up a new position for next time thru*/
  906.    (* LastPos) = ((* LastPos) + CodeBitSize) % 8;
  907.    return NO_ERROR;
  908. }
  909.  
  910.       
  911.  
  912.  
  913.  
  914.  
  915.  
  916. /*
  917. *****************************************************************************
  918. **
  919. **    This writes 8 bit data to the GIF file.
  920. **
  921. ****************************************************************************
  922. */
  923. int WriteGIFdata8(    FILE *        GIFfile, /*pointer to GIF file*/
  924.                         unsigned char   GIFdata  /*8 bit data to write*/
  925.            )
  926. {
  927.    /*write 8 bit data*/
  928.    fwrite((unsigned char *)&GIFdata, sizeof(unsigned char), 1, GIFfile);
  929.    if(ferror(GIFfile))
  930.       /*exit with an error*/
  931.       return ERROR; 
  932.  
  933.    /*exit normally*/
  934.    return NO_ERROR; 
  935. }
  936.  
  937.  
  938. /*
  939. *******************************************************************************
  940. **
  941. **    This writes 16 bit data to the GIF file.  It is in the form
  942. **    lo-byte hi-byte.  It call WriteGIFdata8 to write those bytes
  943. **    to the GIF file.
  944. **
  945. ******************************************************************************
  946. */
  947. int WriteGIFdata16(    FILE *        GIFfile, /*pointer to GIF file*/
  948.                         unsigned int    GIFdata  /*16 bit data to write*/
  949.           )
  950. {
  951.    
  952.    /*break up 16 bit value into lo byte and hi byte*/
  953.    if (WriteGIFdata8(GIFfile, LO_BYTE_16BIT))
  954.       /*exit with an error*/
  955.       return ERROR; 
  956.    else
  957.       if (WriteGIFdata8(GIFfile, HI_BYTE_16BIT))
  958.      /*exit with an error*/
  959.          return ERROR; 
  960.       else
  961.      /*exit normally*/
  962.          return NO_ERROR; 
  963. }
  964.  
  965.    
  966.